use serde::Deserialize;
use serde_json::Value;
use snafu::{ResultExt, ensure_whatever};
use std::path::Path;

#[derive(Debug, Clone)]
pub struct FlowPackage {
    pub base_url: String,
    pub default_timeout_sec: u64,
    pub steps: Vec<FlowStep>,
}

#[derive(Debug, Clone)]
pub struct FlowStep {
    pub interface: String,
    pub items: Vec<Value>,
}

#[derive(Debug, Deserialize)]
struct RawFLow {
    version: u32,
    base_url: String,
    #[serde(default = "default_timeout")]
    default_timeout_sec: u64,
    steps: Vec<RawStep>,
}

const fn default_timeout() -> u64 {
    30
}

#[derive(Debug, Deserialize)]
struct RawStep {
    #[serde(rename = "use")]
    r#use: String,
    items: Vec<Value>,
}

pub async fn load_from_file(path: &Path) -> crate::Result<FlowPackage> {
    let raw_text = tokio::fs::read_to_string(path)
        .await
        .whatever_context("read flow file failed")?;
    let raw =
        serde_json::from_str::<RawFLow>(&raw_text).whatever_context("parse flow file failed")?;

    ensure_whatever!(raw.version == 1, "unexpected flow version");

    let steps = raw
        .steps
        .into_iter()
        .map(|step| FlowStep {
            interface: step.r#use.to_string(),
            items: step.items,
        })
        .collect();

    Ok(FlowPackage {
        base_url: raw.base_url,
        default_timeout_sec: raw.default_timeout_sec,
        steps,
    })
}
